package com.infinitus.activity.util;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import java.io.*;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * @create: 2019/1/9
 * @desc:
 */
public class UrlEncryptor {
    private static String ENCRYPTOR_KEY = "fe09f3ecd2b3404081df4d612176a379";

    private static String APPEND_STRING = "35969a8ca341fa4521a93367b55b5484e0b";
    private static BASE64Decoder decoder = new BASE64Decoder();
    private static BASE64Encoder encoder = new BASE64Encoder();

    public UrlEncryptor() {

    }

    public UrlEncryptor(String key) {
        this.ENCRYPTOR_KEY = key;
    }

    public static void main(String[] args) {
        String str = UrlEncryptor.encrypt("247328916");
        System.out.println(str);
        System.out.println(UrlEncryptor.decrypt("78e7GGLNSaaL%2Bjqxl2DttA8L0iWv20Sn8Pk%2F%2BC332yz6wQhkOJgVrEHYXh80aE2KAj9FtFKUUxv%2B2J%2FR%0ALkweb1%2FEI3V5EBiAtg"));
    }

    public static String encrypt(String userName) {
        try {
            userName = userName + APPEND_STRING;
            userName = URLEncoder.encode(userName, "UTF-8");
            String key = ENCRYPTOR_KEY;
            int ckey_length = 4;
            key = getMd5String(key);
            String keya = getMd5String(key.substring(0, 16));
            String keyb = getMd5String(key.substring(16, 32));
            String min = String.valueOf(System.currentTimeMillis());
            min = "0.00000000 " + min.substring(0, min.length() - 3);
            String keyc = ckey_length > 0 ? getMd5String(String.valueOf(min))
                    : "";
            keyc = keyc.substring(keyc.length() - 4, keyc.length());
            String cryptkey = keya + getMd5String(keya + keyc);
            int key_length = cryptkey.length();
            byte[] temp = null;
            String str_temp = "0000000000"
                    + getMd5String(userName + keyb).substring(0, 16) + userName;
            temp = str_temp.getBytes("UTF-8");
            int[] box = new int[256];
            for (int i = 0; i < box.length; i++) {
                box[i] = i;
            }

            char[] rndkey = new char[256];
            for (int i = 0; i <= 255; i++) {
                rndkey[i] = cryptkey.charAt(i % key_length);
            }

            for (int j = 0, i = 0; i < 256; i++) {
                j = (j + box[i] + (int) rndkey[i]) % 256;
                int tmp = box[i];
                box[i] = box[j];
                box[j] = tmp;
            }
            for (int a = 0, j = 0, i = 0; i < temp.length; i++) {
                a = (a + 1) % 256;
                j = (j + box[a]) % 256;
                int tmp = box[a];
                box[a] = box[j];
                box[j] = tmp;
                int gao = (int) temp[i];
                byte c = (byte) (gao ^ (box[(box[a] + box[j]) % 256]));
                temp[i] = c;
            }
            ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream();
            ByteArrayInputStream bytearrayinputstream = new ByteArrayInputStream(
                    temp);
            encoder.encode(((InputStream) (bytearrayinputstream)),
                    ((OutputStream) (bytearrayoutputstream)));
            String s = bytearrayoutputstream.toString();
            String enKey = keyc + s.replace("=", "");
            return URLEncoder.encode(enKey, "UTF-8");
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private  static String getMd5String(String password)
            throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] input = md.digest(password.getBytes());
        String hex = byteToHexString(input);
        return hex;
    }

    private static String byteToHexString(byte[] res) {
        StringBuffer sb = new StringBuffer(res.length << 1);
        for (int i = 0; i < res.length; i++) {
            String digit = Integer.toHexString(0xFF & res[i]);
            if (digit.length() == 1) {
                digit = '0' + digit;
            }
            sb.append(digit);
        }
        return sb.toString();
    }

    public static boolean matches(String passwordToCheck, String storedPassword) {
        if (storedPassword == null) {
            throw new NullPointerException("storedPassword can not be null");
        }
        if (passwordToCheck == null) {
            throw new NullPointerException("passwordToCheck can not be null");
        }

        return encrypt(passwordToCheck).equals(storedPassword);
    }

    public static String decrypt(String password) {
        try {
            password = URLDecoder.decode(password, "UTF-8");
            int ckey_length = 4;
            String key = getMd5String(ENCRYPTOR_KEY);
            String keya = getMd5String(key.substring(0, 16));
            String min = String.valueOf(System.currentTimeMillis());
            min = "0.00000000 " + min.substring(0, min.length() - 3);

            String keyc = ckey_length > 0 ? password.substring(0, ckey_length)
                    : "";
            String cryptkey = keya + getMd5String(keya + keyc);
            int key_length = cryptkey.length();
            byte[] temp = null;
            if (true) {
                String t1 = password.substring(ckey_length, password.length());
                ByteArrayInputStream bytearrayinputstream = new ByteArrayInputStream(
                        t1.getBytes("UTF-8"));
                ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream();
                decoder.decodeBuffer(((InputStream) (bytearrayinputstream)),
                        ((OutputStream) (bytearrayoutputstream)));
                temp = bytearrayoutputstream.toByteArray();
            }

            int[] box = new int[256];
            for (int i = 0; i < box.length; i++) {
                box[i] = i;
            }

            char[] rndkey = new char[256];
            for (int i = 0; i <= 255; i++) {
                rndkey[i] = cryptkey.charAt(i % key_length);
            }

            for (int j = 0, i = 0; i < 256; i++) {
                j = (j + box[i] + (int) rndkey[i]) % 256;
                int tmp = box[i];
                box[i] = box[j];
                box[j] = tmp;
            }
            StringBuffer sb = new StringBuffer();
            for (int a = 0, j = 0, i = 0; i < temp.length; i++) {
                a = (a + 1) % 256;
                j = (j + box[a]) % 256;
                int tmp = box[a];
                box[a] = box[j];
                box[j] = tmp;
                int gao = (int) temp[i] < 0 ? (int) temp[i] + 256
                        : (int) temp[i];
                char c = (char) (gao ^ (box[(box[a] + box[j]) % 256]));
                sb.append(c);
            }
            String lastStr = sb.substring(26, sb.length());

            lastStr = URLDecoder.decode(lastStr, "UTF-8");
            return lastStr.substring(0, lastStr.indexOf(APPEND_STRING));
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }
}